Kwik.Page.include("Kwik.Ui.Devices.Screen.js");

/** 
* Mouse button enumeration, button name to numeric mapping
* @created 12:02 PM 7/16/2007
* @modified 10:29 AM 4/16/2008
* @singleton 
*/
Kwik.Ui.Devices.MouseButtons = {None:-1, Left:0, Center:1, Right:2};

/** 
* Static mouse object to which mouse tracker can be registerd to obtain mouse status information.
* @requires Kwik.Ui.Devices.Screen
* @requires Kwik.Ui.Devices.MouseButtons
* @created 12:02 PM 7/16/2007
* @modified 10:29 AM 4/16/2008
* @singleton
*/
Kwik.Ui.Devices.Mouse = 
{
	/** Internet explorer buttons map @type Object */
	_ieButtons: {b1:0, b4:1, b2:2},
	/** Mouse position x-coordinate @type Number */
	x: 0,
	/** Mouse position y-coordinate @type Number */
	y: 0,
	/** Mouse button @type Number */
	button: Kwik.Ui.Devices.MouseButtons.None,
	/** List of trackers which receive mouse status changes @type Kwik.Ui.Devices.MouseTracker[] */
	trackers: {},
	/** Amount of trackers registered */
	trackerCount: 0,

	/** Add a mouse tracker to the receive status changes */
	register: function Mouse_register(tracker)
	{
		if(Kwik.Ui.Devices.Mouse.trackerCount == 0)
		{
			Kwik.Ui.Devices.Mouse._attachEvents();
		}

		var id = "tracker" + tracker.ptr.toString();
		if(id in Kwik.Ui.Devices.Mouse.trackers){return;}

		Kwik.Ui.Devices.Mouse.trackers[id] = tracker;
		Kwik.Ui.Devices.Mouse.trackerCount++;
	},

	/** Remove a mouse tracker */
	unregister: function Mouse_unregister(tracker)
	{

		var id = "tracker" + tracker.ptr.toString();
		if(id in Kwik.Ui.Devices.Mouse.trackers)
		{
			delete Kwik.Ui.Devices.Mouse.trackers[id];
			Kwik.Ui.Devices.Mouse.trackerCount--;
		}
		else
		{
			return;
		}
		if(Kwik.Ui.Devices.Mouse.trackerCount == 0)
		{
			Kwik.Ui.Devices.Mouse._detachEvents();
		}
	},
	
	/** Attaches the mouse status listeners to the document */
	_attachEvents: function Mouse__attachEvents()
	{
		Kwik.Page.log.write("Kwik.Ui.Devices.Mouse._attachEvents: Attaching events.");
		Kwik.Utility.attachEvent(document, "onmousemove", Kwik.Ui.Devices.Mouse._mouseMove);
		Kwik.Utility.attachEvent(document, "onmousedown", Kwik.Ui.Devices.Mouse._mouseDown);
		Kwik.Utility.attachEvent(document, "onmouseup", Kwik.Ui.Devices.Mouse._mouseUp);

		if(Kwik.BrowserInfo.gecko)
			Kwik.Utility.attachEvent(window, "onDOMMouseScroll", Kwik.Ui.Devices.Mouse._mouseWheel);
		else
			Kwik.Utility.attachEvent(document, "onmousewheel", Kwik.Ui.Devices.Mouse._mouseWheel);
	},

	/** Detaches the mouse status listeners from the document */
	_detachEvents: function Mouse__detachEvents()
	{
		Kwik.Page.log.write("Kwik.Ui.Devices.Mouse._detachEvents: Detaching events.");
		Kwik.Utility.detachEvent(document, "onmousemove", Kwik.Ui.Devices.Mouse._mouseMove);
		Kwik.Utility.detachEvent(document, "onmousedown", Kwik.Ui.Devices.Mouse._mouseDown);
		Kwik.Utility.detachEvent(document, "onmouseup", Kwik.Ui.Devices.Mouse._mouseUp);

		if(Kwik.BrowserInfo.gecko)
			Kwik.Utility.detachEvent(window, "onDOMMouseScroll", Kwik.Ui.Devices.Mouse._mouseWheel);
		else
			Kwik.Utility.detachEvent(document, "onmousewheel", Kwik.Ui.Devices.Mouse._mouseWheel); 			
	},

	/** Handler for onmousemove events */
	_mouseMove: function Mouse__mouseMove(e)
	{
		if(Kwik.Ui.Devices.Mouse.trackers.length == 0){Kwik.Ui.Devices.Mouse._detachEvents(); return;}
		e = e || event;
		var newX = e.clientX + Kwik.Ui.Devices.Screen.getScrollLeft();
		var newY = e.clientY + Kwik.Ui.Devices.Screen.getScrollTop();

		var changed = this.x != newX || this.y != newY;
		Kwik.Ui.Devices.Mouse.x = newX;
		Kwik.Ui.Devices.Mouse.y = newY;
		if(changed)
		{
			for(e in Kwik.Ui.Devices.Mouse.trackers)
			{
				Kwik.Ui.Devices.Mouse.trackers[e].setPosition(newX, newY);
			}
		}
	},

	/** Handler for onmouseup events */
	_mouseUp: function(e)
	{
		var changed = Kwik.Ui.Devices.Mouse.button != Kwik.Ui.Devices.MouseButtons.None;
		Kwik.Ui.Devices.Mouse.button = Kwik.Ui.Devices.MouseButtons.None;
		if(changed)
		{
			for(e in Kwik.Ui.Devices.Mouse.trackers)
			{
				Kwik.Ui.Devices.Mouse.trackers[e].setButton(Kwik.Ui.Devices.MouseButtons.None);
			}
		}
	},

	/** Handler for onmousedown events */
	_mouseDown: function(e)
	{
		e = e || event;
		var button = Kwik.BrowserInfo.internetExplorer? Kwik.Ui.Devices.Mouse._ieButtons["b" + e.button.toString()]: e.button;
		var changed = Kwik.Ui.Devices.Mouse.button != button;
		Kwik.Ui.Devices.Mouse.button = button;

		if(changed)
		{
			for(e in Kwik.Ui.Devices.Mouse.trackers)
			{
				Kwik.Ui.Devices.Mouse.trackers[e].setButton(button);
			}
		}
	},
	
	_mouseWheel: function(e)
	{
		e = e || event;
		var delta = e.detail*-1 || e.wheelDelta;
		delta = delta < 0? -120: 120;

		for(e in Kwik.Ui.Devices.Mouse.trackers)
		{
			Kwik.Ui.Devices.Mouse.trackers[e].setWheelDelta(delta);
		}
	}
};

/** 
* Pointing device object, tracks mouse events on the document object and reflect it's state.
* @base Kwik.Object 
* @requires Kwik.Object
* @requires Kwik.Ui.Devices.Mouse
* @created 11:25 PM 6/17/2009
* @modified 11:25 PM 6/17/2009
* @constructor 
*/
Kwik.Ui.Devices.MouseTracker = function(config)
{
	/** @ignore */
	Kwik.Utility.extend(this, "Kwik.Object");
	this.__class.push("Kwik.Ui.Devices.MouseTracker");

	/** Mouse position x-coordinate @type Number */
	this.x = 0;
	/** Mouse position y-coordinate @type Number */
	this.y = 0;
	/** Mouse button @type Number */
	this.button = Kwik.Ui.Devices.MouseButtons.None;
	/** Indication whether the tracker is tracking or not @type Boolean */
	this.isTracking = false;
	/** Indication of the mouse wheel movement, up=120 and down=-120  @type Number */
	this.wheelDelta = 0;

	/** Start tracking mouse interaction, optionally a mouse event can be passed to initialize the tracker properties */
	this.start = function MouseTracker_start(evt)
	{
		if(this.isTracking === true){return;}
		if(evt)
		{
			Kwik.Ui.Devices.Mouse.x = this.x = evt.clientX + Kwik.Ui.Devices.Screen.getScrollLeft();
			Kwik.Ui.Devices.Mouse.y = this.y = evt.clientY + Kwik.Ui.Devices.Screen.getScrollTop();
			Kwik.Ui.Devices.Mouse.button = this.button = Kwik.BrowserInfo.internetExplorer? Kwik.Ui.Devices.Mouse._ieButtons["b" + evt.button.toString()]: evt.button;
		}
		this.fireEvent("onbeforestart");

		Kwik.Ui.Devices.Mouse.register(this);
		this.isTracking = true;

		this.fireEvent("onstart");
	};

	/** Stop tracking */
	this.stop = function MouseTracker_stop()
	{
		if(this.isTracking === false){return;}
		this.fireEvent("onbeforestop");

		Kwik.Ui.Devices.Mouse.unregister(this);
		this.isTracking = false;

		this.fireEvent("onstop");
	};

	/** Set the position for this object */
	this.setPosition = function MouseTracker_setPosition(x, y)
	{
		if(this.x == x && this.y == y){return;}
		var diffx = x - this.x;
		var diffy = y - this.y;

		this.fireEvent("onpositionchange", [this.x, this.y, x, y, diffx, diffy]);
		this.x = x;
		this.y = y;
	};

	/** Set the button for this object */
	this.setButton = function MouseTracker_setButton(button)
	{
		if(this.button == button){return;}
		this.fireEvent("onbuttonchange", [this.button, button]);
		this.button = button;
	};

	/** Set the mousewheel movement for this tracker */
	this.setWheelDelta = function MouseTracker_setWheelDelta(delta)
	{
		this.fireEvent("onwheel", [delta]);
		this.wheelDelta = delta;
	};

	/** Configures this mousetracker object */
	this.configure = function MouseTracker_configure(config)
	{
		config = this.Kwik$Object.configure(config);
		if(Kwik.Type.isNumber(config.x)){this.x = config.x;}
		if(Kwik.Type.isNumber(config.y)){this.y = config.y;}
		if(Kwik.Type.isNumber(config.button)){this.button = config.button;}
	};

	/** Get the string represtation of current mouse state */
	this.toString = function()
	{
		return "x=" + this.x + ";y=" + this.y + ";b=" + this.button + ";w=" + this.wheelDelta;
	};
	
	/** Event fired when the mouse position changes */
	this.onpositionchange = function(oldx, oldy, newx, newy, diffx, diffy){};
	/** Event fired when the mouse button changes */
	this.onbuttonchange = function(oldbutton, newbutton){};
	/** Event fired when the mouse button changes */
	this.onwheel = function(oldbutton, newbutton){};

	/** @ignore */
	this.main = function MouseTracker_main(config)
	{
		if(config){this.configure(config);}
	}; this.main(config);
};